-- Rogue Rage
-- Copyright (C) 2012 Darren Grey
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.

require "engine.class"
require "engine.Actor"
-- require "engine.Autolevel"
-- require "engine.interface.ActorTemporaryEffects"
require "engine.interface.ActorLife"
require "engine.interface.ActorProject"
require "engine.interface.ActorLevel"
require "engine.interface.ActorStats"
require "engine.interface.ActorTalents"
require "engine.interface.ActorResource"
require "engine.interface.ActorFOV"
require "mod.class.interface.Combat"
require "engine.interface.ActorInventory"
local Map = require "engine.Map"
local Particles = require "engine.Particles"

module(..., package.seeall, class.inherit(
	engine.Actor,
	engine.interface.ActorInventory,
	-- engine.interface.ActorTemporaryEffects,
	engine.interface.ActorLife,
	engine.interface.ActorProject,
	engine.interface.ActorLevel,
	engine.interface.ActorStats,
	engine.interface.ActorTalents,
	engine.interface.ActorResource,
	engine.interface.ActorFOV,
	mod.class.interface.Combat
))

function _M:init(t, no_default)
	engine.interface.ActorInventory.init(self, t)

	-- Default regen
	t.life_regen = t.life_regen or 0 -- No life regen
	t.life = t.max_life
	t.return_damage = t.return_damage or 0
	t.can_invis = t.can_invis or 0
	t.jumping = t.jumping or 0
	t.vampiric = t.vampiric or 0
	t.pushy = t.pushy or 0
	
	-- Stats
	t.power = t.power or 1
	t.dodge = t.dodge or 1
	t.aim = t.aim or 1
	t.armour = t.armour or 1
	t.speed = t.speed or 0
	
	

	engine.Actor.init(self, t, no_default)
	-- engine.interface.ActorTemporaryEffects.init(self, t)
	engine.interface.ActorLife.init(self, t)
	engine.interface.ActorProject.init(self, t)
	engine.interface.ActorTalents.init(self, t)
	engine.interface.ActorResource.init(self, t)
	engine.interface.ActorStats.init(self, t)
	engine.interface.ActorLevel.init(self, t)
	engine.interface.ActorFOV.init(self, t)
	
	local speed_mod = 1 + (0.1*t.speed)
	if speed_mod < 0.1 then speed_mod = 0.1 end
	
	self.energy.mod = speed_mod
	local value = rng.range(0,1000)
	--self:useEnergy(value)
end

function _M:act()
	if not engine.Actor.act(self) then return end
	
	if game.turn % 10 == 0 then
		self:regenLife()
		
		if self.jumping > 0 and rng.range(1,4) == 1 then
			
			self:teleportRandom(self.x, self.y, 7)
			game.level.map:particleEmitter(self.x, self.y, 1, "teleport_in")
		end
	end
	
	self.changed = true
	
	-- Still enough energy to act ?
	if (self.energy.value < game.energy_to_act) then
		
		return false
	end

	return true
	
end

function _M:move(x, y, force)
	local moved = false
	local ox, oy = self.x, self.y
	if force or self:enoughEnergy() then
		moved = engine.Actor.move(self, x, y, force)
		if not force and moved and (self.x ~= ox or self.y ~= oy) and not self.did_energy then self:useEnergy() end
	end
	self.did_energy = nil

	if moved and not force and ox and oy and (ox ~= self.x or oy ~= self.y) then
		self:setMoveAnim(ox, oy, 3, 10)
		self:setMoveAnim(ox, oy, 1, 8, 8, 0.4)
		
		if self.pushy > 0 then
			--game.level.map:particleEmitter(self.x, self.y, 1, "ball_acid", {radius=1})
			self:project({type="ball",radius=1}, self.x, self.y, function(px, py)
				local target = game.level.map(px, py, engine.Map.ACTOR)
				if not target then return end
			    if target ~= self then
					--self:hitTarget(target, 3)
					local recursive = function(target)
						return true
					end
					target:knockback(self.x, self.y, 1, recursive)
					target:setMoveAnim(target.x, target.y, 4, nil, util.getDir(self.x, self.y, target.x, target.y), 0.5)
				end
			end)
		end
		
	end

	return moved
end

function _M:onTakeHit(value, src)
	
	return value
end

function _M:die(src)
	
	
	engine.interface.ActorLife.die(self, src)

	--[[ Gives the killer some exp for the kill
	if src and src.gainExp then
		src:gainExp(self:worthExp(src))
	end--]]

	return true
end

--[[function _M:levelup()

	-- Heal upon new level
	self.life = self.max_life
end--]]


function _M:attack(target)
	self:bumpInto(target)
end

function _M:useEnergy(val)
	
	engine.Actor.useEnergy(self, val)

	if self.can_invis > 0 then
		local count = 0
		self:project({type="ball",radius=1}, self.x, self.y, function(px, py)
			local target = game.level.map(px, py, engine.Map.ACTOR)
			if target and self:reactionToward(target) < 0 then count = count + 1 end
		end)
		if count == 0 and self.invis == false then
			self.invis = true
			if self._mo then
				self._mo:invalidate()
				game.level.map:updateMap(self.x, self.y)
			end
			self.changed = true
		end
		if count > 0 and self.invis then
			self.invis = false
			if self._mo then
				self._mo:invalidate()
				game.level.map:updateMap(self.x, self.y)
			end
			self.changed = true
		end
	end
end

--- Attach or remove a display callback
-- Defines particles to display
function _M:defineDisplayCallback()
	if not self._mo then return end

	local function tactical(x, y, w, h, zoom, on_map, tlx, tly)
		-- Tactical info
		if game.level and game.always_target then
			-- Tactical life info
			if on_map then
				local dh = h * 0.1
				local lp = math.max(0, self.life) / self.max_life + 0.0001
--				if game.party:hasMember(self) and fully_rested then -- blue (party members only)
--					core.display.drawQuad(x + 3, y + h - dh, (w - 6) * lp, dh, 26, 131, 162, 255)
				if lp > .75 then -- green
					core.display.drawQuad(x + 3, y + h - dh, w - 6, dh, 129, 180, 57, 128)
					core.display.drawQuad(x + 3, y + h - dh, (w - 6) * lp, dh, 50, 220, 77, 255)
				elseif lp > .5 then -- yellow
					core.display.drawQuad(x + 3, y + h - dh, w - 6, dh, 175, 175, 10, 128)
					core.display.drawQuad(x + 3, y + h - dh, (w - 6) * lp, dh, 240, 252, 35, 255)
				elseif lp > .25 then -- orange
					core.display.drawQuad(x + 3, y + h - dh, w - 6, dh, 185, 88, 0, 128)
					core.display.drawQuad(x + 3, y + h - dh, (w - 6) * lp, dh, 255, 156, 21, 255)
				else -- red
					core.display.drawQuad(x + 3, y + h - dh, w - 6, dh, 167, 55, 39, 128)
					core.display.drawQuad(x + 3, y + h - dh, (w - 6) * lp, dh, 235, 0, 0, 255)
				end
			end
		end

	end

	self._mo:displayCallback(function(x, y, w, h, zoom, on_map, tlx, tly)
		tactical(tlx or x, tly or y, w, h, zoom, on_map)
		return true
	end)
end

--- How much experience is this actor worth
-- @param target to whom is the exp rewarded
-- @return the experience rewarded
function _M:worthExp(target)

	return 0
end

--- Can the actor see the target actor
-- This does not check LOS or such, only the actual ability to see it.<br/>
-- Check for telepathy, invisibility, stealth, ...
function _M:canSee(actor, def, def_pct)
	if not actor then return false, 0 end

	-- Check for invis
	if actor.invis and actor ~= self then return false, 0
	else
		return true, 100
	end
	
	-- Make sure the display updates
	if self.player and type(def) == "nil" and actor._mo then actor._mo:onSeen(res) end
end

